package server

import (
	"fmt"
	"github.com/go-kratos/kratos/cmd/kratos/v2/util"
	"os"
	"path/filepath"
	"strings"
)

func (o *Object) domain() error {
	//filename
	filename := filepath.Join(o.rootPath, DomainPath+"/domain_gen.go")
	flag, err := util.PathExists(filename)
	if err != nil {
		return err
	}

	// 拼接好struct
	body := o.domainDody()
	bodyStart := "// ------------------------ gen " + o.Filename + " start ---------------------------"
	bodyEnd := "// ------------------------ gen " + o.Filename + " end ---------------------------"

	if flag {
		return o.domainExists(filename, body, bodyStart, bodyEnd)
	}

	content := fmt.Sprintf(domainTmp, o.rootPkg, bodyStart, body, bodyEnd)

	return os.WriteFile(filename, []byte(content), 0o644)
}

func (o *Object) domainExists(filename, body, bodyStart, bodyEnd string) error {

	var isExistsNew bool
	content, err := util.AddContentToFile(filename, bodyStart, func(s string) {}, func(positionStartIdx, positionEndIdx int, contents []string) []string {
		if positionStartIdx == -1 {
			// 不存在当前内容
			content := fmt.Sprintf(domainStructAddTmp, bodyStart, body, bodyEnd)
			isExistsNew = true
			return append(contents, content)
		}
		for i, content := range contents[positionStartIdx:] {
			if strings.Contains(content, bodyEnd) {
				positionEndIdx = positionStartIdx + i
				break
			}
		}
		// 在接口处添加内容
		contents = append(contents[:positionStartIdx+2], append([]string{body}, contents[positionEndIdx:]...)...)
		isExistsNew = true
		return contents
	})
	if err != nil || !isExistsNew {
		return err
	}

	os.Remove(filename)

	return os.WriteFile(filename, []byte(content), 0o644)
}

func (o *Object) domainDody() string {
	var res string
	for _, message := range o.Messages {
		var field string
		for _, f := range message.Fields {
			_, ok := o.MessageRecord[f.Type]
			if !ok {
				field += fmt.Sprintf(strutFieldTmp, util.ToUpperx(f.Name), f.Type, f.Name)
			} else {
				field += fmt.Sprintf("\t%s *%s `json:\"%s\"`\n", util.ToUpperx(f.Name), f.Type, f.Name)
			}

		}
		res += fmt.Sprintf(domainStructTmp, message.Name, field)

		//gen func
		res += o.domainPbToFunc(message)
		res += o.domainToPbFunc(message)
	}

	return res
}

func (o *Object) domainToPbFunc(msg *Message) string {
	var structField string
	for _, f := range msg.Fields {
		_, ok := o.MessageRecord[f.Type]
		if !ok {
			// a: api.a
			structField += fmt.Sprintf(toPbFuncField, util.ToUpperx(f.Name), util.ToUpperx(f.Name))
			continue
		}

		structField += fmt.Sprintf(toPbSubFuncField, util.ToUpperx(f.Name), util.ToUpperx(f.Name))
	}

	return fmt.Sprintf(domainToPbFunc, msg.Name, msg.Name, msg.Name, structField) + "\n"
}

func (o *Object) domainPbToFunc(msg *Message) string {
	var structField string
	for _, f := range msg.Fields {
		_, ok := o.MessageRecord[f.Type]
		if !ok {
			// a: api.a
			structField += fmt.Sprintf(pbToFuncField, util.ToUpperx(f.Name), util.ToUpperx(f.Name))
			continue
		}

		structField += fmt.Sprintf(pbToSubFuncField, util.ToUpperx(f.Name), f.Type, util.ToUpperx(f.Name))
	}

	return fmt.Sprintf(domainPbToFunc, msg.Name, msg.Name, msg.Name, msg.Name, structField) + "\n"
}
